# 描述了将插件添加到菜单或工具栏的过程、后面介绍的对话框的初始化过程、调用插件时的回调过程等
import pathlib

from qgis.PyQt.QtWidgets import (QDialog, QVBoxLayout, QListWidget, 
                                QPushButton, QLabel, QHBoxLayout, 
                                QComboBox, QAction, QListWidgetItem)
from qgis.PyQt.QtCore import Qt
from qgis.PyQt.QtGui import QIcon, QColor
from qgis.core import (QgsProject, QgsWkbTypes, QgsMapLayer, QgsFeatureRequest)
from qgis.gui import (QgsVertexMarker, QgsRubberBand)

from .ereamaptool import AreaMapTool
class TestPlugin:
    def __init__(self, iface):
        self.iface = iface
        self.dlg = None
    def initGui(self):
        self.action = QAction(QIcon(":/plugis/test_plugins/icon.png"), "设施点必须在端点上",self.iface.mainWindow())
        self.action.triggered.connect(self.run)
        self.iface.addToolBarIcon(self.action)
        self.iface.addPluginToMenu("检查", self.action)

    def unload(self):
        self.iface.removePluginMenu("检查", self.action)
        self.iface.removeToolBarIcon(self.action)
        del self.action
    def run(self):
        if not self.dlg:
            self.dlg = TopoCheckDialog(self.iface)
        self.dlg.show()
        self.dlg.raise_()
        self.dlg.activateWindow()
class TopoCheckDialog(QDialog):
    def __init__(self, iface):
        super().__init__()
        self.iface = iface
        self.setWindowTitle("相关设施是否在线的端点上")
        self.setMinimumWidth(400)
        # 窗体布局方式
        self.layout = QVBoxLayout()
        self.setLayout(self.layout)
        # 地图交互绘制指定的范围
        self.select_area_btn = QPushButton("选择检查区域")
        self.select_area_btn.clicked.connect(self.start_area_selection)
        self.layout.addWidget(self.select_area_btn)

        self.area_label = QLabel("未选择区域全量数据检查")
        self.layout.addWidget(self.area_label)

        # 需要判断的点线图层
        self.layer_layout = QHBoxLayout()

        self.layer_layout.addWidget(QLabel("点图层名称:"))
        self.point_layer_combo = QComboBox()
        self.layer_layout.addWidget(self.point_layer_combo)

        self.layer_layout.addWidget(QLabel("线图层名称:"))
        self.line_layer_combo = QComboBox()
        self.layer_layout.addWidget(self.line_layer_combo)

        self.layout.addLayout(self.layer_layout)

        self.populate_layers() # 将图层分类加入点线的复选框中
        QgsProject.instance().layersAdded.connect(self.populate_layers) # 监听图层添加
        QgsProject.instance().layersRemoved.connect(self.populate_layers) # 监听图层移除

        # 开始检查
        self.check_btn = QPushButton("检查")
        self.check_btn.clicked.connect(self.check_point_overlap_endpoint) # 点必须与端点重叠
        self.layout.addWidget(self.check_btn)

        # 结果列表方便修改错误
        self.results_label = QLabel("待检查，暂无数据...")
        self.layout.addWidget(self.results_label)
        self.results_list = QListWidget()
        self.results_list.itemClicked.connect(self.zoom_to_error) # 点击错误列表，移动到错误的位置
        self.layout.addWidget(self.results_list)

        # 取消
        self.cancel_btn = QPushButton("取消")
        self.cancel_btn.clicked.connect(self.close) # 点必须与端点重叠
        self.layout.addWidget(self.cancel_btn)

        # 相关的变量
        self.map_tool = None
        self.markers = []  # 需要标记的错误点
        self.selection_geom = None # 检查的区域
        self.canvas = iface.mapCanvas()

    def zoom_to_error(self, item):
        '''
        移动到错误的位置
        '''
        point_layer = self.point_layer_combo.currentData()
        feat_id = item.data(Qt.UserRole)
        if point_layer and feat_id:
            self.iface.mapCanvas().zoomToFeatureIds(point_layer, [feat_id])
    def clear_markers(self):
        '''
        取消标记
        '''
        for marker in self.markers:
            self.iface.mapCanvas().scene().removeItem(marker)
        self.markers = []
    def closeEvent(self, event):
        '''
        关闭
        '''
        super().closeEvent(event)
        self.close()

    def close(self):
        self.results_label.setText("待检查，暂无数据...")
        self.clear_markers()
        if self.map_tool:
            self.iface.mapCanvas().unsetMapTool(self.map_tool)
        
        self.selection_geom = None # 检查的区域
        self.area_label.setText("未选择区域全量数据检查")
        self.results_list.clear()
        if self.selection_rubber:
            self.selection_rubber.reset()
    def populate_layers(self):
        '''
        过滤当前图层中的点线图层
        '''
        self.point_layer_combo.clear()
        self.line_layer_combo.clear()

        for layer in QgsProject.instance().mapLayers().values():
            if layer.type() == QgsMapLayer.VectorLayer:
                if layer.geometryType() == QgsWkbTypes.PointGeometry:
                    self.point_layer_combo.addItem(layer.name(), layer)
                elif layer.geometryType() == QgsWkbTypes.LineGeometry:
                    self.line_layer_combo.addItem(layer.name(), layer)
    def start_area_selection(self):
        '''
        开始绘制检查区域
        '''
        if not self.map_tool:
            self.map_tool = AreaMapTool(self.iface.mapCanvas(), self.iface.cadDockWidget(), self)
            self.map_tool.selectionFinished.connect(self.area_selected)
        self.iface.mapCanvas().setMapTool(self.map_tool)
        self.area_label.setText("检查区域绘制中(右键结束绘制)")

    def area_selected(self, geometry):
        '''
        结束绘制检查区域
        '''
        # self.selection_geom = geometry
        # centroid = geometry.centroid().asPoint()
        # self.area_label.setText(f"绘制区域中心点坐标为： ({centroid.x():.2f}, {centroid.y():.2f})")   
        # 清除之前的临时图形
        if hasattr(self, 'selection_rubber'):
            self.selection_rubber.reset(QgsWkbTypes.PolygonGeometry)
        else:
            # 创建新的橡皮筋对象（用于临时图形）
            self.selection_rubber = QgsRubberBand(self.canvas, QgsWkbTypes.PolygonGeometry)

            # 设置样式：红色虚线边框，透明填充
            line_style = Qt.DashLine
            self.selection_rubber.setStrokeColor(QColor(255, 0, 0))  # 红色边框
            self.selection_rubber.setLineStyle(line_style)           # 虚线样式
            self.selection_rubber.setFillColor(QColor(255, 0, 0, 0)) # 完全透明填充 (alpha=0)

        # 添加几何面到临时图形
        self.selection_rubber.addGeometry(geometry, None)

        # 保存几何对象并更新标签
        self.selection_geom = geometry
        centroid = geometry.centroid().asPoint()
        self.area_label.setText(f"绘制区域中心点坐标为： ({centroid.x():.2f}, {centroid.y():.2f})")

    # 拓扑检查
    def check_point_overlap_endpoint(self):
        '''
        相关的设施点必须在管点的起始或终止端点
        '''
        self.results_label.setText("检查中，请等待...")
        self.results_list.clear()
        self.clear_markers()
        
        point_layer = self.point_layer_combo.currentData() 
        line_layer = self.line_layer_combo.currentData()
        
        if not point_layer or not line_layer:
            return
            
        # Collect endpoints (only within selection if specified)
        endpoints = set()
        line_features = line_layer.getFeatures()
        if self.selection_geom:
            line_features = line_layer.getFeatures(QgsFeatureRequest().setFilterRect(self.selection_geom.boundingBox()))
            
        for line_feat in line_features:
            geom = line_feat.geometry()
            if not geom or geom.isEmpty():
                continue
                
            if self.selection_geom and not geom.intersects(self.selection_geom):
                continue
                
            if geom.isMultipart():
                for part in geom.constParts():
                    if part.numPoints() > 0:
                        endpoints.add((part.startPoint().x(), part.startPoint().y()))
                        endpoints.add((part.endPoint().x(), part.endPoint().y()))
            else:
                if geom.constGet().numPoints() > 0:
                    endpoints.add((geom.constGet().startPoint().x(), geom.constGet().startPoint().y()))
                    endpoints.add((geom.constGet().endPoint().x(), geom.constGet().endPoint().y()))
        
        # Check points
        point_features = point_layer.getFeatures()
        if self.selection_geom:
            point_features = point_layer.getFeatures(QgsFeatureRequest().setFilterRect(self.selection_geom.boundingBox()))
            
        for point_feat in point_features:
            geom = point_feat.geometry()
            if not geom or geom.isEmpty():
                continue
                
            if self.selection_geom and not geom.intersects(self.selection_geom):
                continue
                
            point = geom.asPoint()
            found = any(abs(point.x() - ep[0]) < 1e-8 and abs(point.y() - ep[1]) < 1e-8 for ep in endpoints)
            
            if not found:
                item = QListWidgetItem(f"Point ID {point_feat.id()} at ({point.x():.2f}, {point.y():.2f})")
                item.setData(Qt.UserRole, point_feat.id())
                self.results_list.addItem(item)
                
                marker = QgsVertexMarker(self.iface.mapCanvas())
                marker.setCenter(point)
                marker.setColor(Qt.red)
                marker.setIconSize(8)
                marker.setIconType(QgsVertexMarker.ICON_CROSS)
                marker.setPenWidth(2)
                self.markers.append(marker)
        if len(self.markers) == 0:
            self.results_label.setText("未发现错误")
        else:
            self.results_label.setText("检查完毕，错误列表为：")